package com.blackcat.v1.connector;

import com.blackcat.v1.Connector;
import com.blackcat.v1.Container;
import com.blackcat.v1.Request;
import com.blackcat.v1.Response;
import com.blackcat.v1.net.DefaultServerSocketFactory;
import com.blackcat.v1.net.ServerSocketFactory;
import lombok.extern.slf4j.Slf4j;


import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Stack;


/**
 * 职责：等待请求,获取socket
 */
@Slf4j
public class HttpConnector implements Runnable, Connector {

    //最大 process的数量
    private final static int MAX_PROCESSES = 20;
    //最小 process的数量
    private final static int MIN_PROCESSES = 5;
    //当前 process的标记
    private int curProcesses;
    //socketFactory
    private ServerSocketFactory factory = null;

    //process的缓存池 是否存在缓存池的处理策略（min<curProcessors<max && 空闲的时候）
    private Stack<HttpProcessor> processors = new Stack<HttpProcessor>();

    //ip
    private String address = "127.0.0.1";
    //端口
    private int port = 80;

    private int acceptCount = 10;
    //容器
    private Container container;

    @Override
    public void run() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = open();
        } catch (IOException e) {
            e.printStackTrace();
        }
        while (true) {
            Socket socket = null;
            try {
                //阻塞获取嵌套字
                socket = serverSocket.accept();
                HttpProcessor processor = getProcesser();
                processor.assign(socket);

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private ServerSocket open() throws IOException {
        // Acquire the server socket factory for this Connector
        ServerSocketFactory factory = getFactory();

        // If no address is specified, open a connection on all addresses
        if (address == null) {
            return (factory.createSocket(port, acceptCount));
        }

        // Open a server socket on the specified address
        try {
            InetAddress is = InetAddress.getByName(address);
            return (factory.createSocket(port, acceptCount, is));
        } catch (Exception e) {
            return (factory.createSocket(port, acceptCount));
        }

    }

    public ServerSocketFactory getFactory() {

        if (this.factory == null) {
            synchronized (this) {
                this.factory = new DefaultServerSocketFactory();
            }
        }
        return (this.factory);
    }

    @Override
    public void setFactory(ServerSocketFactory factory) {
        this.factory = factory;
    }


    private HttpProcessor getProcesser() {
        if (processors.size() >= MAX_PROCESSES)
            return null;
        else if (processors.size() > 0) {
            return processors.pop();
        } else {
            return newProcesser(this);
        }
    }

    @Override
    public Container getContainer() {
        return this.container;
    }

    @Override
    public void setContainer(Container container) {
        this.container = container;
    }


    @Override
    public boolean getEnableLookups() {
        return false;
    }

    @Override
    public void setEnableLookups(boolean enableLookups) {

    }


    @Override
    public String getInfo() {
        return null;
    }

    @Override
    public int getRedirectPort() {
        return 0;
    }

    @Override
    public void setRedirectPort(int redirectPort) {

    }

    @Override
    public String getScheme() {
        return null;
    }

    @Override
    public void setScheme(String scheme) {

    }

    @Override
    public boolean getSecure() {
        return false;
    }

    @Override
    public void setSecure(boolean secure) {

    }

    @Override
    public Request createRequest() {
        return null;
    }

    @Override
    public Response createResponse() {
        return null;
    }



    public void start() {
        Thread t = new Thread(this);
        //启动当前线程
        t.start();
        for (int i = 0; i < MIN_PROCESSES; i++) {
            //创建处理器并放入缓存池
            recycle(newProcesser(this));
        }
    }

    private HttpProcessor newProcesser(HttpConnector connector) {
        HttpProcessor processor = new HttpProcessor(connector, curProcesses++);
        processor.start();
        return processor;
    }

    public void recycle(HttpProcessor httpProcessor) {
        processors.push(httpProcessor);
        log.debug("after push [{}]", processors.size());
    }
}
